package org.smart4j.framework.util;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * description: 类的操作工具类 。 获取类加载器，加载类等。
 * @version v1.0
 * @author w
 * @date 2018年8月26日下午9:42:31
 *
 */
public final class ClassUtil {
	
	private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
	
	/**
	 * description: 获取类加载器
	 * @return
	 * ClassLoader
	 * @version v1.0
	 * @author w
	 * @date 2018年8月26日 下午9:48:27
	 */
	public static ClassLoader getClassLoader(){
		return Thread.currentThread().getContextClassLoader();
	}
	
	/**
	 * description: 加载类
	 * @param className 类文件名
	 * @param isInit 是否初始化  --- 是否执行类的静态代码块 。	 
	 * @return
	 * Class<?>
	 * @version v1.0
	 * @author w
	 * @date 2018年8月26日 下午9:49:36
	 * @see java.lang.Class.forName();
	 */
	public static Class<?> loadClass(String className,boolean isInit){
		 Class<?> clzz ;
		 try {
			 clzz = Class.forName(className, isInit, getClassLoader());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			logger.error("load class failure :",e);
			throw new RuntimeException(e);
		}
		return clzz;
	}
	
	public static Class<?> loadClass(String className){
		return loadClass(className, true);
	}
	/**
	 * description: 获取指定包名下的所有类 
	 * @param packageName
	 * @return
	 * Set<Class<?>>
	 * @version v1.0
	 * @author w
	 * @date 2018年8月26日 下午9:50:50
	 */
	public static Set<Class<?>> getClassSet(String packageName){
		Set<Class<?>> set = new HashSet<Class<?>>();
		try {
			Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
			while(urls.hasMoreElements()){
				URL url = urls.nextElement();
				if(null != url){
					String protocol = url.getProtocol();
					if("file".equals(protocol)){
						String packagePath = url.getPath().replaceAll("%20", "");
						addClass(set,packagePath,packageName);
					}else if("jar".equals(protocol)){
						JarURLConnection jarURLConnection =(JarURLConnection) url.openConnection();
						if(null != jarURLConnection){
							JarFile jarFile = jarURLConnection.getJarFile();
							if(null != jarFile){
								Enumeration<JarEntry> jarEntries = jarFile.entries();
								while(jarEntries.hasMoreElements()){
									JarEntry jarEntry = jarEntries.nextElement();
									String jarEntryName = jarEntry.getName();
									if(jarEntryName.endsWith(".class")){
										String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
										doAddClass(className,set);
									}
								}
							}
						}
					}
						
				}
			}
		} catch (IOException e) {
			logger.error("get class set failure ,",e);
			throw new RuntimeException(e);
		}
		return set;
	}
	
	/**
	 * description: 加载 class 
	 * @param className
	 * @param set
	 * void
	 * @version v1.0
	 * @author w
	 * @date 2018年8月27日 下午9:55:34
	 */
	private static void doAddClass(String className, Set<Class<?>> set) {
		Class<?> clzz = loadClass(className, false);
		set.add(clzz);
	}

	private static void addClass(Set<Class<?>> set, String packagePath, String packageName) {
		File[] files = new File(packagePath).listFiles(new FileFilter() {
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
			}
		});
		for (File file : files) {
			String fileName = file.getName();
			if(file.isFile()){
				String className = fileName.substring(0, fileName.lastIndexOf("."));
				if(StringUtils.isNotEmpty(className)){
					className=packageName.concat(".").concat(className);
					doAddClass(className, set);
				}
			}else{
				// 子包路径
				String subPackagePath=fileName;
				if(StringUtils.isNotEmpty(packagePath)){
					subPackagePath=packagePath.concat("/").concat(subPackagePath);
				}
				// 子包名
				String subPackageName=fileName;
				if(StringUtils.isNotEmpty(packageName)){
					subPackageName=packageName.concat(".").concat(subPackageName);
				}
				// 递归获取当前包下的子包信息
				addClass(set, subPackagePath, subPackageName);
			}
		} // end foreach 
	}
	
	
}
